#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <signal.h>

#include <pthread.h>

#include "debug/debug.h"
#include "configs/config.h"
#include "module/module.h"
#include "tools/str.h"
#include "global.h"

static char FilePath[2048];

static const FileData fileDataClass[]={
    {.fileNameClass=".html",.fileType="text/html"},
    {.fileNameClass=".jpg",.fileType="image/jpg"},
    {.fileNameClass=".png",.fileType="image/png"},
    {.fileNameClass=".css",.fileType="text/css"},
};

int initServer();
int handClient(int fd);
void * WebHandleThread(void * arg);
void sighandler(int signo);

//线程池
pthread_t handleThreadPool[THREAD_POOL_NUM];
static int hanleNum = 0;
static int handleAllNUM=THREAD_POOL_NUM;

typedef struct _SERVICE_THREAD_STATUS_
{
    pthread_t handleThread;
    int ClientFd;
}SERVICE_THREAD_STATUS;


int main(int agrc,char **agrv){

    int serverFd = initServer();
    if (serverFd == ERROR)
    {
        WEB_DEBUG(DEBUG_ERROR,"init servicer is error\n");
    }
    
    struct sockaddr_in caddr;
    int size = sizeof(caddr);
    signal(SIGPIPE, sighandler);

    while (1)
    {
        memset(&caddr,0,size);
        int clientFd = accept(serverFd,(struct sockaddr *)(&caddr),&size);
        if (-1 == clientFd)
        {
            WEB_DEBUG(DEBUG_ERROR,"servicer is error\n");
            break;
        }else{
            WEB_DEBUG(DEBUG_INFO,"client connected\n");
            WEB_DEBUG(DEBUG_INFO,"clientFd:%d\n",clientFd);
            //创建线程处理该次请求
            if (hanleNum < handleAllNUM)
            {
                SERVICE_THREAD_STATUS ServiceThreadStatus;
                if(pthread_create(&handleThreadPool[hanleNum], NULL, (void *)WebHandleThread, (void *)&clientFd) != 0){
                    WEB_DEBUG(DEBUG_ERROR,"pthread_create fail\n");
                }else{
                    hanleNum++;
                }
            }
        }
    }
    WEB_DEBUG(DEBUG_INFO,"exit byb byb!!!\n");
    return 0;
}


void * WebHandleThread(void * VclientFd){
    int clientFd = (*((int *)VclientFd));
    WEB_DEBUG(DEBUG_INFO,"beginning(*((int *)clientFd：%d));\n",clientFd);
    // handClient(clientFd);
    // close(clientFd);
    // WEB_DEBUG(DEBUG_INFO,"close(*((int *)clientFd：%d));\n",clientFd);
    while (1)
    {
        if(handClient(clientFd)==EXIT_FUN){
            WEB_DEBUG(DEBUG_INFO,"close(*((int *)clientFd：%d));\n",clientFd);
            close(clientFd);
            break;
        }
    }
    // exit(0);
}

int initServer(){
    int fd;

    if(ConfigMiniWeb(CONFIG_SERVICE_CONFIGURE_PATH,&base_data) == -1){
        WEB_DEBUG(DEBUG_ERROR,"config mini web service failed\n");
        return ERROR;
    }

    fd = socket(AF_INET,SOCK_STREAM,0);
    if ( -1 == fd)
    {
        WEB_DEBUG(DEBUG_ERROR,"create socket failed\n");
        goto exit_fun;
    }
    WEB_DEBUG(DEBUG_INFO,"create socket success\n");

    struct sockaddr_in addr = {0};

    addr.sin_family = AF_INET;
    addr.sin_port = htons(base_data.port);
    addr.sin_addr.s_addr = inet_addr(base_data.ip);  //INADDR_ANY;//inet_addr("192.168.3.1");

    int r = bind(fd,(struct sockaddr *)&addr,sizeof(addr));
    if (-1 == r)
    {
        WEB_DEBUG(DEBUG_ERROR,"bind\n");
        goto exit_fun;
    }
    WEB_DEBUG(DEBUG_INFO,"bind success\n");

    r = listen(fd,10);
    if (-1 == r)
    {
        WEB_DEBUG(DEBUG_ERROR,"listen\n");
        goto exit_fun;
    }
    WEB_DEBUG(DEBUG_INFO,"listen success\n");
    
    return fd;
exit_fun:
    close(fd);
    return ERROR;
}

//信号处理函数
void sighandler(int signo)
{
    printf("signo==[%d]\n", signo);
}

/**
 * @brief 信息处理接口
 * @param fd 客户端连接符
 * @return int 
 */
int handClient(int fd){
    int ret = RUN_FUN;
    char buff[1024*1024] = {0};
    char fileBuff[1024*1023] = {0};
    char response[1024*1024] = {0};

    int r = read(fd,buff,sizeof(buff));
    //请求头的数据
    WEB_DEBUG(DEBUG_ALL,"buff:%s\n",buff);
    if (r > 0 )
    {
        char fileName[20]={0};
        char urlData[256]={0};
        char tableData[512]={0};
        char requestClass[4]={0};
        // sscanf(buff,"GET /%s HTTP/1.1",fileName);
            //判断是什么请求GET还是POST
        sscanf(buff,"%[^ ]",requestClass);
        sscanf(buff,"%*[^/]/%[^ ]",urlData);

        WEB_DEBUG(DEBUG_ALL,"requestClass:%s\n",requestClass);

        //否则打开默认文件
        //判断有没有请求到文件，如果没有就放回默认文件
        //判断是什么请求，如果是GET请求，判断有没有参数，有就获取参数
        if (StrCmp(requestClass,"GET") == EQUAL)
        {
            if (StrLenght(urlData) > 0)
            {
                //分割出数据和文件名
                StrSplit(fileName,urlData,'?');
                StrCopy(tableData,urlData+StrLenght(fileName)+1);
                WEB_DEBUG(DEBUG_ALL,"table data(%s)\n",tableData);
            }else{
                sscanf(base_data.html_file_name,"%s",fileName);
            }
        }else if (StrCmp(requestClass,"POST") == EQUAL)
        {
            /* code */
        }
        
        WEB_DEBUG(DEBUG_INFO,"fileName:%s\n",fileName);
        
        char mime[64]={0};
        for (size_t i = 0; i < sizeof(fileDataClass)/sizeof(FileData); i++)
        {
            
            if (strstr(fileName,fileDataClass[i].fileNameClass)){
                StrCopy(mime,(const char *)(fileDataClass[i].fileType));
                break;
            }
        }
        
        
        sprintf(FilePath,"%s%s",base_data.html_path,fileName);
        WEB_DEBUG(DEBUG_INFO,"file path is %s \n",FilePath);
        FILE *filefp = fopen(FilePath,"rb");
        memset(FilePath,0,sizeof(FilePath));
        size_t fileLen = 0;
        size_t responseLen = 0;
        size_t dataLength = 0;
        if (filefp == NULL)
        {
error:
            WEB_DEBUG(DEBUG_WARN,"%s open failed !!!\n",fileName);
            sprintf(response,"HTTP/1.1 404 Not Found\r\nContent-Type:%s\r\n\r\n",mime);
            responseLen = strlen(response);
            sprintf(FilePath,"%s%s",base_data.html_path,base_data.html_file_404);
            int errfd = open(FilePath,O_RDONLY);
            if(errfd > 0)
            {
                fileLen = read(errfd,responseLen+response,sizeof(response)-responseLen);
                close(errfd);
            }
            dataLength=responseLen+fileLen;
            ret = EXIT_FUN;
        }else{
            WEB_DEBUG(DEBUG_INFO,"open %s success\n",fileName);
            fileLen = fread(fileBuff,1,sizeof(fileBuff),filefp);
            fclose(filefp);
            WEB_DEBUG(DEBUG_ALL,"call static moudel\n"); 
            dataLength = StaticModule(mime,fileBuff,fileLen,response,sizeof(response));
            ret = EXIT_FUN;
        }
        
        if(write(fd,response,dataLength) < 0){
            ret = EXIT_FUN;
        }

    }else{
        ret = EXIT_FUN;
        goto exit_fun;
    }
    WEB_DEBUG(DEBUG_INFO,"return data:\n%s\n",response);
    //usleep(1000*500);
exit_fun:
    return ret;
}

